<html>
<head>
  <title>Thread</title>
  <basefont face="微软雅黑" size="2" />
  <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
  <meta name="exporter-version" content="Evernote Windows/307027 (zh-CN, DDL); Windows/6.1.0 (Win32);"/>
  <style>
    body, td {
      font-family: 微软雅黑;
      font-size: 10pt;
    }
  </style>
</head>
<body>
<a name="622"/>
<h1>Thread</h1>

<div>
<span><div><div><div><a href="https://docs.python.org/2/library/threading.html">https://docs.python.org/2/library/threading.html</a></div><div><ul><li>Thread Objects</li><li>Lock Objects</li><li>RLock Objects</li><li>Condition Objects</li><li>Semaphore Objects</li><li>Event Objects</li><li>Timer Objects</li></ul><div><br/></div></div><div><br/></div><div><br/></div><div style="text-align: center;"><font color="#1C3387" style="font-size: 24pt;"><span style="color: rgb(28, 51, 135); font-size: 24pt; font-weight: bold;">多线程基础</span></font></div><div style="text-align: center;"><br/></div><div><ul><li><font style="font-size: 12pt;"><span style="line-height: 1.45; font-size: 12pt; font-weight: bold;">threading.Thread</span></font></li></ul><div><span style="font-size: 12pt; font-weight: bold;">使用多线程并发的操作</span></div></div><div style="box-sizing: border-box; padding: 8px; font-size: 12px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902);"><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">#!/usr/bin/python</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">import threading</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">import time</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">def worker():</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">    print &quot;worker&quot;</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">    time.sleep(1)</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">    return</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">for i in xrange(5):</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">    t = threading.Thread(target=worker)</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">    t.start()</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">############# 完成时间为1.3 s ，大大缩短</span></div></div><div>  </div><div><ul><li><font style="font-size: 12pt;"><span style="font-size: 12pt; font-weight: bold;">threading.activeCount()</span></font></li></ul></div><div>返回当前进程中线程的个数。返回的个数中包含主线程</div><div style="box-sizing: border-box; padding: 8px; font-size: 12px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902);"><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">#!/usr/bin/python</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">#current's number of threads</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">import threading</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">import time</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;"> </span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">def worker():</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">    print &quot;test&quot;</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">    time.sleep(1)</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;"> </span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">for i in xrange(5):</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">    t = threading.Thread(target=worker)</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">    t.start()</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;"> </span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">print &quot;current has %d threads&quot; % (threading.activeCount() - 1)</span></div></div><div><br/></div><div><ul><li><font style="font-size: 12pt;"><span style="font-size: 12pt; font-weight: bold;">threading.enumerate()</span></font></li></ul></div><div>此方法返回当前运行中的Thread对象列表。</div><div style="box-sizing: border-box; padding: 8px; font-size: 12px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902);"><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">for item in threading.enumerate():</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">    print item</span></div></div><div><br/></div><div><ul><li><font style="font-size: 12pt;"><span style="font-size: 12pt; font-weight: bold;">threading.setDaemon()</span></font></li></ul></div><div>设置后台进程</div><div style="box-sizing: border-box; padding: 8px; font-size: 12px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902);"><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">t=threading.Thread(target=worker)</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">t.setDaemon(True)</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">t.start()</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">print &quot;haha&quot;</span></div></div><div><br/></div><div><ul><li><font style="font-size: 12pt;"><span style="font-family: 'Microsoft YaHei'; font-size: 12pt; font-weight: bold;">join([timeout])</span></font></li></ul></div><div><span style="font-family: 'Microsoft YaHei';">阻塞当前上下文环境的线程，直到调用此方法的线程终止或到达指定的timeout（可选参数）</span></div><div style="box-sizing: border-box; padding: 8px; font-size: 12px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902);"><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(0, 0, 255); font-family: 'Microsoft YaHei';">for</span> <span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: 'Microsoft YaHei';">i</span> <span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(0, 0, 255); font-family: 'Microsoft YaHei';">in</span> <span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: 'Microsoft YaHei';">xrange(4</span><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(0, 0, 0); font-family: 'Microsoft YaHei';">):</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(0, 0, 0); font-family: 'Microsoft YaHei';">    t</span> <span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: 'Microsoft YaHei';">=threading.Thread(target=action,args=</span><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(0, 0, 0); font-family: 'Microsoft YaHei';">(i,))</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(0, 0, 0); font-family: 'Microsoft YaHei';">    t.setDaemon(True)</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(0, 0, 0); font-family: 'Microsoft YaHei';">    thread_list.append(t)</span></div><div><br style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);"/></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(0, 0, 255); font-family: 'Microsoft YaHei';">for</span> <span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: 'Microsoft YaHei';">t</span> <span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(0, 0, 255); font-family: 'Microsoft YaHei';">in</span> <span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(0, 0, 0); font-family: 'Microsoft YaHei';">thread_list:</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(0, 0, 0); font-family: 'Microsoft YaHei';">    t.start()</span></div><div><br style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);"/></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(0, 0, 255); font-family: 'Microsoft YaHei';">for</span> <span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: 'Microsoft YaHei';">t</span> <span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(0, 0, 255); font-family: 'Microsoft YaHei';">in</span> <span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(0, 0, 0); font-family: 'Microsoft YaHei';">thread_list:</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(0, 0, 0); font-family: 'Microsoft YaHei';">    t.join()</span></div></div><div><span style="color: rgb(0, 0, 0); font-family: 'Microsoft YaHei';">设置join之后，主线程等待子线程全部执行完成后或者子线程超时后，主线程才结束。</span></div><div><br/></div><div><span style="font-family: 'Microsoft YaHei';"><font style="font-size: 12pt;"><span style="font-family: 'Microsoft YaHei'; font-size: 12pt; font-weight: bold;">join不妥当</span></font>的用法，使多线程编程顺序执行</span></div><div style="box-sizing: border-box; padding: 8px; font-size: 12px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902);"><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(0, 0, 255); font-family: 'Microsoft YaHei';">for</span> <span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: 'Microsoft YaHei';">i</span> <span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(0, 0, 255); font-family: 'Microsoft YaHei';">in</span> <span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: 'Microsoft YaHei';">xrange(4</span><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(0, 0, 0); font-family: 'Microsoft YaHei';">):</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(0, 0, 0); font-family: 'Microsoft YaHei';">    t</span> <span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: 'Microsoft YaHei';">=threading.Thread(target=action,args=</span><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(0, 0, 0); font-family: 'Microsoft YaHei';">(i,))</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(0, 0, 0); font-family: 'Microsoft YaHei';">    t.setDaemon(True)</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(0, 0, 0); font-family: 'Microsoft YaHei';">    t.start()</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(0, 0, 0); font-family: 'Microsoft YaHei';">    t.join()</span></div></div><div><br/></div><div><br/></div><h2><span style="font-family: 'Microsoft YaHei'; color: rgb(28, 51, 135); font-size: 18pt;">Lock、Rlock类</span></h2><div><span style="font-family: 'Microsoft YaHei';">由于线程之间随机调度：某线程可能在执行n条后，CPU接着执行其他线程。为了多个线程同时操作一个内存中的资源时不产生混乱，我们使用锁。</span></div><div style="margin-top: 1em; margin-bottom: 1em;"><span style="font-family: 'Microsoft YaHei';">Lock（指令锁）是可用的最低级的同步指令。Lock处于锁定状态时，不被特定的线程拥有。Lock包含两种状态——锁定和非锁定，以及两个基本的方法。</span></div><div style="margin-top: 1em; margin-bottom: 1em;"><span style="font-family: 'Microsoft YaHei';">可以认为Lock有一个锁定池，当线程请求锁定时，将线程至于池中，直到获得锁定后出池。池中的线程处于状态图中的同步阻塞状态。</span></div><div style="margin-top: 1em; margin-bottom: 1em;"><span style="font-family: 'Microsoft YaHei';">RLock（可重入锁）是一个可以被同一个线程请求多次的同步指令。RLock使用了“拥有的线程”和“递归等级”的概念，处于锁定状态时，RLock被某个线程拥有。拥有RLock的线程可以再次调用acquire()，释放锁时需要调用release()相同次数。</span></div><div style="margin-top: 1em; margin-bottom: 1em;"><span style="font-family: 'Microsoft YaHei';">可以认为RLock包含一个锁定池和一个初始值为0的计数器，每次成功调用 acquire()/release()，计数器将+1/-1，为0时锁处于未锁定状态。</span></div><div><span style="font-family: 'Microsoft YaHei'; font-weight: bold;">简言之：Lock属于全局，Rlock属于线程。</span></div><div><br/></div><div><span style="font-family: 'Microsoft YaHei'; font-weight: bold;">构造方法： </span></div><div style="margin-top: 1em; margin-bottom: 1em;"><span style="font-family: 'Microsoft YaHei';">Lock()，Rlock（）,</span><span style="font-family: 'Microsoft YaHei'; font-style: italic; font-weight: bold;">推荐使用Rlock()</span></div><div><span style="font-family: 'Microsoft YaHei'; font-weight: bold;">实例方法： </span></div><div><span style="font-family: 'Microsoft YaHei';">　　acquire([timeout]): 尝试获得锁定。使线程进入同步阻塞状态。 </span></div><div><span style="font-family: 'Microsoft YaHei';">　　release(): 释放锁。使用前线程必须已获得锁定，否则将抛出异常。</span></div><div><br/></div><div style="box-sizing: border-box; padding: 8px; font-size: 12px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902);"><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: 'Microsoft YaHei'; font-size: 12px;">gl_num = 0</span></div><div><br style="font-family: Microsoft YaHei;"/></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: 'Microsoft YaHei'; font-size: 12px;">lock = threading.RLock()</span></div><div><br style="font-family: Microsoft YaHei;"/></div><div><br style="font-family: Microsoft YaHei;"/></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: 'Microsoft YaHei'; font-size: 12px;"># 调用acquire([timeout])时，线程将一直阻塞，</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: 'Microsoft YaHei'; font-size: 12px;"># 直到获得锁定或者直到timeout秒后（timeout参数可选）。</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: 'Microsoft YaHei'; font-size: 12px;"># 返回是否获得锁。</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: 'Microsoft YaHei'; font-size: 12px;">def Func():</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: 'Microsoft YaHei'; font-size: 12px;">    lock.acquire()</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: 'Microsoft YaHei'; font-size: 12px;">    global gl_num</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: 'Microsoft YaHei'; font-size: 12px;">    gl_num += 1</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: 'Microsoft YaHei'; font-size: 12px;">    time.sleep(1)</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: 'Microsoft YaHei'; font-size: 12px;">    print gl_num</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: 'Microsoft YaHei'; font-size: 12px;">    lock.release()</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(0, 0, 255); font-family: 'Microsoft YaHei';">for</span> <span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: 'Microsoft YaHei';">i</span> <span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(0, 0, 255); font-family: 'Microsoft YaHei';">in</span> <span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: 'Microsoft YaHei';">range(10</span><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(0, 0, 0); font-family: 'Microsoft YaHei';">):</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(0, 0, 0); font-family: 'Microsoft YaHei';">    t</span> <span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: 'Microsoft YaHei';">= threading.Thread(target=</span><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(0, 0, 0); font-family: 'Microsoft YaHei';">Func)</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(0, 0, 0); font-family: 'Microsoft YaHei';">    t.start()</span></div></div><div style="box-sizing: border-box; padding: 8px; font-size: 12px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902);"><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: 'Microsoft YaHei'; font-size: 12px;">1</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: 'Microsoft YaHei'; font-size: 12px;">2</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: 'Microsoft YaHei'; font-size: 12px;">3</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: 'Microsoft YaHei'; font-size: 12px;">4</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: 'Microsoft YaHei'; font-size: 12px;">5</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: 'Microsoft YaHei'; font-size: 12px;">6</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: 'Microsoft YaHei'; font-size: 12px;">7</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: 'Microsoft YaHei'; font-size: 12px;">8</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: 'Microsoft YaHei'; font-size: 12px;">9</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: 'Microsoft YaHei'; font-size: 12px;">10</span></div><div><br style="font-family: Microsoft YaHei;"/></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: 'Microsoft YaHei'; font-size: 12px;">Process finished with exit code 0</span></div></div><div><span style="font-family: 'Microsoft YaHei';">可以看出，</span><font style="font-size: 12pt;"><span style="font-family: 'Microsoft YaHei'; color: rgb(173, 0, 0); font-size: 12pt; font-weight: bold;">全局变量在在每次被调用时都要获得锁</span></font><span style="font-family: 'Microsoft YaHei';">，才能操作，因此保证了共享数据的安全性</span></div><div><br/></div><div><br/></div><h2><span style="font-family: 'Microsoft YaHei'; font-weight: bold; color: rgb(28, 51, 135); font-size: 18pt;">Condition类</span></h2><div><span style="font-family: 'Microsoft YaHei';">Condition（条件变量）通常与一个锁关联。</span></div><div><span style="font-family: 'Microsoft YaHei';">可以认为，除了Lock带有的锁定池外，Condition还包含一个等待池，池中的线程处于等待阻塞状态，直到另一个线程调用notify()/notifyAll()通知；得到通知后线程进入锁定池等待锁定。</span></div><div><span style="font-family: 'Microsoft YaHei'; font-weight: bold;">构造方法： </span></div><div style="-en-paragraph: true; margin-top: 1em; margin-bottom: 1em;"><span style="-en-paragraph: true; font-family: 'Microsoft YaHei';">Condition([lock/rlock])</span></div><div><span style="font-family: 'Microsoft YaHei'; font-weight: bold;">实例方法： </span></div><div><span style="font-family: 'Microsoft YaHei';">　　acquire([timeout])/release(): 调用关联的锁的相应方法。 </span></div><div><span style="font-family: 'Microsoft YaHei';">　　wait([timeout]): 调用这个方法将使线程进入Condition的等待池等待通知，并释放锁。使用前线程必须已获得锁定，否则将抛出异常。 </span></div><div><span style="font-family: 'Microsoft YaHei';">　　notify(): 调用这个方法将从等待池挑选一个线程并通知，收到通知的线程将自动调用acquire()尝试获得锁定（进入锁定池）；其他线程仍然在等待池中。调用这个方法不会释放锁定。使用前线程必须已获得锁定，否则将抛出异常。 </span></div><div><span style="-en-paragraph: true; font-family: 'Microsoft YaHei';">　　notifyAll(): 调用这个方法将通知等待池中所有的线程，这些线程都将进入锁定池尝试获得锁定。调用这个方法不会释放锁定。使用前线程必须已获得锁定，否则将抛出异常。</span></div><div style="box-sizing: border-box; padding: 8px; font-family: Monaco, Menlo, Consolas, &quot;Courier New&quot;, monospace; font-size: 12px; color: rgb(51, 51, 51); border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902); background-position: initial initial; background-repeat: initial initial;-en-codeblock:true;"><div><span style="font-family: Microsoft YaHei; color: rgb(0, 0, 255);">import threading</span></div><div><span style="font-family: Microsoft YaHei; color: rgb(0, 0, 255);">alist = None</span></div><div><span style="font-family: Microsoft YaHei; color: rgb(0, 0, 255);">condition = threading.Condition()</span></div><div><span style="font-family: Microsoft YaHei; color: rgb(0, 0, 255);">def doSet():</span></div><div><span style="font-family: Microsoft YaHei; color: rgb(0, 0, 255);">    if condition.acquire():</span></div><div><span style="font-family: Microsoft YaHei; color: rgb(0, 0, 255);">        while alist is None:</span></div><div><span style="font-family: Microsoft YaHei; color: rgb(0, 0, 255);">            condition.wait()</span></div><div><span style="font-family: Microsoft YaHei; color: rgb(0, 0, 255);">        for i in range(len(alist))[::-1]:</span></div><div><span style="font-family: Microsoft YaHei; color: rgb(0, 0, 255);">            alist[i] = 1</span></div><div><span style="font-family: Microsoft YaHei; color: rgb(0, 0, 255);">        condition.release()</span></div><div><span style="font-family: Microsoft YaHei; color: rgb(0, 0, 255);">def doPrint():</span></div><div><span style="font-family: Microsoft YaHei; color: rgb(0, 0, 255);">    if condition.acquire():</span></div><div><span style="font-family: Microsoft YaHei; color: rgb(0, 0, 255);">        while alist is None:</span></div><div><span style="font-family: Microsoft YaHei; color: rgb(0, 0, 255);">            condition.wait()</span></div><div><span style="font-family: Microsoft YaHei; color: rgb(0, 0, 255);">        for i in alist:</span></div><div><span style="font-family: Microsoft YaHei; color: rgb(0, 0, 255);">            print i,</span></div><div><span style="font-family: Microsoft YaHei; color: rgb(0, 0, 255);">        print</span></div><div><span style="font-family: Microsoft YaHei; color: rgb(0, 0, 255);">        condition.release()</span></div><div><span style="font-family: Microsoft YaHei; color: rgb(0, 0, 255);">def doCreate():</span></div><div><span style="font-family: Microsoft YaHei; color: rgb(0, 0, 255);">    global alist</span></div><div><span style="font-family: Microsoft YaHei; color: rgb(0, 0, 255);">    if condition.acquire():</span></div><div><span style="font-family: Microsoft YaHei; color: rgb(0, 0, 255);">        if alist is None:</span></div><div><span style="font-family: Microsoft YaHei; color: rgb(0, 0, 255);">            alist = [0 for i in range(10)]</span></div><div><span style="font-family: Microsoft YaHei; color: rgb(0, 0, 255);">            condition.notifyAll()</span></div><div><span style="font-family: Microsoft YaHei; color: rgb(0, 0, 255);">        condition.release()</span></div><div><span style="font-family: Microsoft YaHei; color: rgb(0, 0, 255);">tset = threading.Thread(target=doSet,name='tset')</span></div><div><span style="font-family: Microsoft YaHei; color: rgb(0, 0, 255);">tprint = threading.Thread(target=doPrint,name='tprint')</span></div><div><span style="font-family: Microsoft YaHei; color: rgb(0, 0, 255);">tcreate = threading.Thread(target=doCreate,name='tcreate')</span></div><div><span style="font-family: Microsoft YaHei; color: rgb(0, 0, 255);">tset.start()</span></div><div><span style="font-family: Microsoft YaHei; color: rgb(0, 0, 255);">tprint.start()</span></div><div><span style="font-family: Microsoft YaHei; color: rgb(0, 0, 255);">tcreate.start()</span></div></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><h2><span style="font-family: 'Microsoft YaHei'; font-weight: bold;"><font style="font-size: 18pt; color: rgb(28, 51, 135);">Event类</font></span></h2><div><span style="-en-paragraph: true; font-family: 'Microsoft YaHei';">Event（事件）是最简单的线程通信机制之一：一个线程通知事件，其他线程等待事件。Event内置了一个初始为False的标志，当调用set()时设为True，调用clear()时重置为 False。wait()将阻塞线程至等待阻塞状态。</span></div><div style="-en-paragraph: true; margin-top: 1em; margin-bottom: 1em;"><span style="-en-paragraph: true; font-family: 'Microsoft YaHei';">　　Event其实就是一个简化版的 Condition。Event没有锁，无法使线程进入同步阻塞状态。</span></div><div><span style="font-family: 'Microsoft YaHei'; font-weight: bold;">构造方法： </span></div><div style="-en-paragraph: true; margin-top: 1em; margin-bottom: 1em;"><span style="-en-paragraph: true; font-family: 'Microsoft YaHei';">Event()</span></div><div><span style="font-family: 'Microsoft YaHei'; font-weight: bold;">实例方法： </span></div><div><span style="font-family: 'Microsoft YaHei';">　　isSet(): 当内置标志为True时返回True。 </span></div><div><span style="font-family: 'Microsoft YaHei';">　　set(): 将标志设为True，并通知所有处于等待阻塞状态的线程恢复运行状态。 </span></div><div><span style="font-family: 'Microsoft YaHei';">　　clear(): 将标志设为False。 </span></div><div><span style="-en-paragraph: true; font-family: 'Microsoft YaHei';">　　wait([timeout]): 如果标志为True将立即返回，否则阻塞线程至等待阻塞状态，等待其他线程调用set()。</span></div><div><br/></div><div style="box-sizing: border-box; padding: 8px; font-family: Monaco, Menlo, Consolas, &quot;Courier New&quot;, monospace; font-size: 12px; color: rgb(51, 51, 51); border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902); background-position: initial initial; background-repeat: initial initial;-en-codeblock:true;"><div># encoding: UTF-8</div><div>import threading</div><div>import time</div><div>event = threading.Event()</div><div>def func():</div><div>    # 等待事件，进入等待阻塞状态</div><div>    print '%s wait for event...' % threading.currentThread().getName()</div><div>    event.wait()</div><div>    # 收到事件后进入运行状态</div><div>    print '%s recv event.' % threading.currentThread().getName()</div><div>t1 = threading.Thread(target=func)</div><div>t2 = threading.Thread(target=func)</div><div>t1.start()</div><div>t2.start()</div><div>time.sleep(2)</div><div># 发送事件通知</div><div>print 'MainThread set event.'</div><div>event.set()</div></div><div style="box-sizing: border-box; padding: 8px; font-family: Monaco, Menlo, Consolas, &quot;Courier New&quot;, monospace; font-size: 12px; color: rgb(51, 51, 51); border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902); background-position: initial initial; background-repeat: initial initial;-en-codeblock:true;"><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">Thread-1 wait for event...</span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">Thread-2 wait for event...</span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">#2秒后。。。</span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">MainThread set event.</span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">Thread-1 recv event.</span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">Thread-2 recv event.</span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">Process finished with exit code 0</span></div></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><h2><span style="font-family: 'Microsoft YaHei'; font-weight: bold;"><font style="font-size: 18pt; color: rgb(28, 51, 135);">timer类</font></span></h2><div><span style="-en-paragraph: true; font-family: 'Microsoft YaHei';">Timer（定时器）是Thread的派生类，用于在指定时间后调用一个方法。</span></div><div><span style="font-family: 'Microsoft YaHei'; font-weight: bold;">构造方法： </span></div><div><span style="font-family: 'Microsoft YaHei';">Timer(interval, function, args=[], kwargs={}) </span></div><div><span style="font-family: 'Microsoft YaHei';">　　interval: 指定的时间 </span></div><div><span style="font-family: 'Microsoft YaHei';">　　function: 要执行的方法 </span></div><div style="-en-paragraph: true; margin-top: 1em; margin-bottom: 1em;"><span style="-en-paragraph: true; font-family: 'Microsoft YaHei';">　　args/kwargs: 方法的参数</span></div><div><span style="font-family: 'Microsoft YaHei'; font-weight: bold;">实例方法： </span></div><div><span style="-en-paragraph: true; font-family: 'Microsoft YaHei';">Timer从Thread派生，没有增加实例方法。</span></div><div style="box-sizing: border-box; padding: 8px; font-family: Monaco, Menlo, Consolas, &quot;Courier New&quot;, monospace; font-size: 12px; color: rgb(51, 51, 51); border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902); background-position: initial initial; background-repeat: initial initial;-en-codeblock:true;"><div># encoding: UTF-8</div><div>import threading</div><div>def func():</div><div>    print 'hello timer!'</div><div>timer = threading.Timer(5, func)</div><div>timer.start()</div></div><div><span style="font-family: 'Microsoft YaHei';">线程延迟5秒后执行。</span></div><div><br/></div><div><br/></div><div><br/></div><h2><span style="font-family: 'Microsoft YaHei'; font-weight: bold;"><font style="font-size: 18pt; color: rgb(28, 51, 135);">local类</font></span></h2><div><span style="-en-paragraph: true; font-family: 'Microsoft YaHei';">local是一个小写字母开头的类，用于管理 thread-local（线程局部的）数据。对于同一个local，线程无法访问其他线程设置的属性；线程设置的属性不会被其他线程设置的同名属性替换。</span></div><div><span style="-en-paragraph: true; font-family: 'Microsoft YaHei';">　　可以把local看成是一个“线程-属性字典”的字典，local封装了从自身使用线程作为 key检索对应的属性字典、再使用属性名作为key检索属性值的细节。</span></div><div style="box-sizing: border-box; padding: 8px; font-family: Monaco, Menlo, Consolas, &quot;Courier New&quot;, monospace; font-size: 12px; color: rgb(51, 51, 51); border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902); background-position: initial initial; background-repeat: initial initial;-en-codeblock:true;"><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);"># encoding: UTF-8</span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">import threading</span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">local = threading.local()</span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">local.tname = 'main'</span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">def func():</span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">    local.tname = 'notmain'</span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">    print local.tname</span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">t1 = threading.Thread(target=func)</span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">t1.start()</span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">t1.join()</span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">print local.tname</span></div></div><div style="box-sizing: border-box; padding: 8px; font-family: Monaco, Menlo, Consolas, &quot;Courier New&quot;, monospace; font-size: 12px; color: rgb(51, 51, 51); border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902); background-position: initial initial; background-repeat: initial initial;-en-codeblock:true;"><div><span style="color: #000000; font-family: 'Microsoft YaHei'; font-size: 9pt;">notmain</span></div><div><span style="color: #000000; font-family: 'Microsoft YaHei'; font-size: 9pt;">main</span></div></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div style="text-align: center;"><font color="#1C3387" style="font-size: 24pt;"><span style="color: rgb(28, 51, 135); font-size: 24pt; font-weight: bold;">多线程应用</span></font></div><div style="text-align: center;"><br/></div><div>threading 库<font style="font-size: 12pt;"><span style="font-size: 12pt; color: rgb(173, 0, 0); font-weight: bold;">可以在单独的线程中执行任何的在 Python 中可以调用的对象</span></font>。你可以创建一个 Thread 对象并将你要执行的对象以 target 参数的形式提供给该对象。 下面是一个简单的例子：</div><div style="box-sizing: border-box; padding: 8px; font-size: 12px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902);"><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;"># Code to execute in an independent threadimport timedef countdown(n):</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">while n &gt; 0:</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">    print('T-minus', n)</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">    n -= 1</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">    time.sleep(5)</span></div><div><br style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);"/></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;"># Create and launch a threadfrom threading import Threadt = Thread(target=countdown, args=(10,))</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">t.start()</span></div></div><div><br/></div><div><ul><li>当你创建好一个线程对象后，该对象并不会立即执行，除非你调用它的 start() 方法（当你调用 start() 方法时，它会调用你传递进来的函数，并把你传递进来的参数传递给该函数）。</li><li>Python中的线程会在一个单独的系统级线程中执行（比如说一个 POSIX 线程或者一个 Windows 线程），这些线程将由操作系统来全权管理。</li><li>线程一旦启动，将独立执行<font style="font-size: 14pt;"><span style="font-size: 14pt; color: rgb(173, 0, 0); font-weight: bold;">直到目标函数返回</span></font>。你可以查询一个线程对象的状态，看它是否还在执行：</li></ul></div><div><br/></div><div><br/></div><div><font style="font-size: 16pt;"><span style="font-size: 16pt; color: rgb(173, 0, 0); font-weight: bold;">将一个线程加入到当前线程，并等待它终止：</span></font></div><div style="box-sizing: border-box; padding: 8px; font-size: 12px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902);"><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">t.join()</span></div></div><div><br/></div><div>Python解释器直到所有线程都终止前仍保持运行。对于需要长时间运行的线程或者需要一直运行的后台任务，你应当考虑使用后台线程。 例如：</div><div style="box-sizing: border-box; padding: 8px; font-size: 12px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902);"><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">t = Thread(target=countdown, args=(10,), daemon=True)</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">t.start()</span></div></div><div><br/></div><div><font color="#1C3387" style="font-size: 12pt;"><span style="font-size: 12pt; color: rgb(28, 51, 135); font-weight: bold;">后台线程无法等待，不过，这些线程会在主线程终止时自动销毁。</span></font></div><div><div><br/></div><table style="border-collapse: collapse; min-width: 100%;"><colgroup><col style="width: 267px;"></col><col style="width: 291px;"></col></colgroup><tbody><tr><td style="border: 1px solid rgb(204, 204, 204); width: 267px; padding: 8px;"><div>可以对线程做的事情：</div><div><br/></div><div>t.join()</div><div>t.start()</div></td><td style="border: 1px solid rgb(204, 204, 204); width: 291px; padding: 8px;"><div>不能对线程做的事：</div><div><br/></div><div>无法结束一个线程</div><div>无法给它发送信号</div><div>无法调整它的调度</div><div>无法执行其他高级操作</div></td></tr></tbody></table><div><font style="font-size: 14pt;"><span style="font-size: 14pt; color: rgb(50, 135, 18); font-weight: bold;">如果需要这些特性，你需要自己添加。</span></font>比如说，如果你需要终止线程，那么这个线程必须通过编程在某个特定点轮询来退出。你可以像下边这样把线程放入一个类中：</div></div><div style="box-sizing: border-box; padding: 8px; font-size: 12px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902);"><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">class CountdownTask:</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">    def __init__(self):</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">        self._running = True</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">    </span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">    def terminate(self):</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">        self._running = False</span></div><div><br/></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">    def run(self, n):</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">        while self._running and n &gt; 0:</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">            print('T-minus', n)</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">            n -= 1</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">            time.sleep(5)</span></div><div><br/></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">c = CountdownTask()</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">t = Thread(target=c.run, args=(10,))</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">t.start()</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">c.terminate()</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">t.join()        #Wait for actual termination(if needed)</span></div></div><div><br/></div><div>如果线程执行一些像I/O这样的阻塞操作，那么通过轮询来终止线程将使得线程之间的协调变得非常棘手。比如，如果一个线程一直阻塞在一个I/O操作上，它就永远无法返回，也就无法检查自己是否已经被结束了。要正确处理这些问题，你需要利用超时循环来小心操作线程。</div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><h1 style="text-align: left;"><span style="color: rgb(28, 51, 135); font-size: 18pt;">判断线程是否已经启动</span></h1><div>线程的一个关键特性是每个线程都是独立运行且状态不可预测。如果程序中的其他线程需要通过判断某个线程的状态来确定自己下一步的操作，这时线程同步问题就会变得非常棘手。</div><div><br/></div><div>使用 threading 库中的 Event 对象。 Event 对象包含一个可由线程设置的信号标志，它允许线程等待某些事件的发生。</div><div><br/></div><div>如果有线程等待一个 event 对象，而这个 event 对象的标志为假，那么这个线程将会被一直阻塞直至该标志为真。一个线程如果将一个 event 对象的信号标志设置为真，它将唤醒所有等待这个 event 对象的线程。</div><div style="box-sizing: border-box; padding: 8px; font-size: 12px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902);"><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">from threading import Thread, Eventimport time</span></div><div><br style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);"/></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;"># Code to execute in an independent thread</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">def countdown(n, started_evt):</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">    print('countdown starting')</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco; font-size: 12px;"><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">    </span><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">started_evt.set()           </span> <font style="font-size: 11pt;"><span style="background-color: rgb(251, 250, 248); color: rgb(50, 135, 18); font-family: Monaco; font-size: 11pt; font-weight: bold;"># 调用event对象中的set() 函数，t线程中这个event对象      </span></font></span></div><div><font style="font-size: 11pt;"><span style="background-color: rgb(251, 250, 248); color: rgb(50, 135, 18); font-family: Monaco; font-size: 11pt; font-weight: bold;">                                        #set（）函数为假</span></font></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">    while n &gt; 0:</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">        print('T-minus', n)</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">        n -= 1</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">        time.sleep(5)</span></div><div><br style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);"/></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;"># Create the event object that will be used to signal startup</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">started_evt = Event()     </span><font style="font-size: 11pt;"><span style="background-color: rgb(251, 250, 248); color: rgb(50, 135, 18); font-family: Monaco; font-size: 11pt; font-weight: bold;">#将Event对象作为参数传入进程中运行的函数（对象）</span></font></div><div><br style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);"/></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;"># Launch the thread and pass the startup event</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">print('Launching countdown')</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">t = Thread(target=countdown, args=(10,started_evt))</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">t.start()</span></div><div><br style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);"/></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;"># Wait for the thread to start</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">started_evt.wait()</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">print('countdown is running')</span></div></div><div><br/></div><div>event 对象最好单次使用，就是说，你创建一个 event 对象，让某个线程等待这个对象，一旦这个对象被设置为真，你就应该丢弃它。尽管可以通过 clear() 方法来重置 event 对象，但是很难确保安全地清理 event 对象并对它重新赋值。</div><div>        很可能会发生错过事件、死锁或者其他问题（特别是，你无法保证重置 event 对象的代码会在线程再次等待这个 event 对象之前执行）。</div><div>        如果一个线程需要不停地重复使用 event 对象，你最好使用 <font style="font-size: 14pt;"><span style="color: rgb(173, 0, 0); font-size: 14pt; font-weight: bold;">Condition 对象</span></font>来代替。下面的代码使用 Condition 对象实现了一个周期定时器，每当定时器超时的时候，其他线程都可以监测到：</div><div><br/></div><div><br/></div><div>event对象的一个重要特点是当它被设置为真时会唤醒所有等待它的线程。如果你只想唤醒单个线程，最好是使用信号量或者 Condition 对象来替代。</div><div><br/></div><div><br/></div><div><br/></div></div><div style="text-align: left;"><font style="font-size: 18pt;"><span style="color: rgb(28, 51, 135); font-size: 18pt; font-weight: bold;">线程间通信</span></font></div><div style="text-align: left;"><br/></div><div style="text-align: left;"><div><font style="font-size: 14pt;"><span style="color: rgb(173, 0, 0); font-size: 14pt; font-weight: bold;">在这些线程之间安全地交换信息或数据</span></font></div></div><div style="text-align: left;"><br/></div><div style="text-align: left;"><div><font style="font-size: 14pt;"><span style="color: rgb(50, 135, 18); font-size: 14pt; font-weight: bold;">从一个线程向另一个线程发送数据最安全的方式可能就是使用 queue 库中的队列了。</span></font></div></div><div style="text-align: left;"><div>创建一个被多个线程共享的 Queue 对象，这些线程通过使用 put() 和 get() 操作来向队列中添加或者删除元素。 例如：</div></div><div style="text-align: left;"><br/></div><div style="text-align: left;">Queue 对象已经<font style="font-size: 14pt;"><span style="color: rgb(28, 51, 135); font-size: 14pt; font-weight: bold;">包含了必要的锁</span></font>，所以你可以通过它在多个线程间多安全地共享数据。 当使用队列时，协调生产者和消费者的<font style="font-size: 14pt;"><span style="color: rgb(173, 0, 0); font-size: 14pt; font-weight: bold;">关闭问题</span></font>可能会有一些麻烦。一个通用的解决方法是在队列中放置一个特殊的值，当消费者读到这个值的时候，终止执行。</div><div style="text-align: left;"><br/></div><div style="box-sizing: border-box; padding: 8px; font-size: 12px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902);"><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">from queue import Queuefrom threading import Thread</span></div><div><br/></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;"># Object that signals shutdown_sentinel = object()</span></div><div><br/></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;"># A thread that produces datadef producer(out_q):</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">    while running:</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">        # Produce some data</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">        ...</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">        out_q.put(data)</span></div><div><br/></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">    # Put the sentinel on the queue to indicate completion</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">    out_q.put(_sentinel)</span></div><div><br/></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;"># A thread that consumes datadef consumer(in_q):</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">    while True:</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">        # Get some data</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">        data = in_q.get()</span></div><div><br/></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">        # Check for termination</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">        if data is _sentinel:</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">            in_q.put(_sentinel)</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">            break</span></div><div><br/></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">        # Process the data</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">        ...</span></div><div><br/></div></div><div style="text-align: left;"><div>本例中有一个特殊的地方：消费者在读到这个特殊值之后立即又把它放回到队列中，将之传递下去。这样，所有监听这个队列的消费者线程就可以全部关闭了。 尽管队列是最常见的线程间通信机制，但是仍然可以自己通过创建自己的数据结构并添加所需的锁和同步机制来实现线程间通信。最常见的方法是使用 Condition 变量来包装你的数据结构。</div></div><div style="text-align: left;"><br/></div><div style="text-align: left;"><div><font style="font-size: 18pt;"><span style="color: rgb(28, 51, 135); font-size: 18pt; font-weight: bold;">创建一个线程安全的优先级队列</span></font></div></div><div style="text-align: left;"><br/></div><div style="text-align: left;"><br/></div><div style="box-sizing: border-box; padding: 8px; font-size: 12px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902);"><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">import heapq</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">import threading</span></div><div><br/></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">class PriorityQueue:</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">    def __init__(self):</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">        self._queue = []</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">        self._count = 0</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">        self._cv = threading.Condition()</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">    def put(self, item, priority):</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">        with self._cv:</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">            heapq.heappush(self._queue, (-priority, self._count, item))</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">            self._count += 1</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">            self._cv.notify()</span></div><div><br/></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">    def get(self):</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">        with self._cv:</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">            while len(self._queue) == 0:</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">                self._cv.wait()</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">            return heapq.heappop(self._queue)[-1]</span></div><div><br/></div></div><div style="text-align: left;"><br/></div><div style="text-align: left;"><br/></div><div style="text-align: left;"><br/></div><div style="text-align: left;"><br/></div><div style="text-align: left;"><br/></div><div style="text-align: left;"><br/></div><div style="text-align: left;"></div><h1 style="text-align: left;"><span style="color: rgb(28, 51, 135); font-size: 18pt;">给关键部分加锁</span></h1><div style="text-align: left;"><div><font style="font-size: 16pt;"><span style="color: rgb(50, 135, 18); font-size: 16pt; font-weight: bold;">对多线程程序中的临界区加锁以避免竞争条件。</span></font></div></div><div style="text-align: left;"><font style="font-size: 18pt;"><span style="color: rgb(173, 0, 0); font-size: 18pt; font-weight: bold;">lock对象</span></font></div><div style="text-align: left;"><div>要在多线程程序中安全使用可变对象，你需要使用 threading 库中的 Lock 对象，就像下边这个例子这样：</div></div><div style="text-align: left;"><br/></div><div style="box-sizing: border-box; padding: 8px; font-size: 12px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902);"><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">import threading</span></div><div><br/></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">class SharedCounter:</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">    '''    A counter object that can be shared by multiple threads.    '''</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">    def __init__(self, initial_value = 0):</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">        self._value = initial_value</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">        self._value_lock = threading.Lock()</span></div><div><br/></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">    def incr(self,delta=1):</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">        '''        Increment the counter with locking        '''</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">        with self._value_lock:</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">             self._value += delta</span></div><div><br/></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">    def decr(self,delta=1):</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">        '''        Decrement the counter with locking        '''</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">        with self._value_lock:</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">             self._value -= delta</span></div><div><br/></div></div><div style="text-align: left;"><br/></div><div style="text-align: left;"><div>Lock 对象和 with 语句块一起使用可以保证互斥执行，就是每次只有一个线程可以执行 with 语句包含的代码块。with 语句会在这个代码块执行前自动获取锁，在执行结束后自动释放锁。</div></div><div style="text-align: left;"><br/></div><div style="text-align: left;"><div>线程调度本质上是不确定的，<font style="font-size: 12pt;"><span style="color: rgb(173, 0, 0); font-size: 12pt; font-weight: bold;">因此，在多线程程序中错误地使用锁机制可能会导致随机数据损坏或者其他的异常行为，我们称之为竞争条件</span></font>。为了避免竞争条件，最好只在临界区（对临界资源进行操作的那部分代码）使用锁。</div></div><div style="text-align: left;"><br/></div><div style="text-align: left;"><div>为了避免出现死锁的情况，使用锁机制的程序应该设定为每个线程一次只允许获取一个锁。<font style="font-size: 12pt;"><span style="color: rgb(173, 0, 0); font-size: 12pt; font-weight: bold;">RLock</span></font> 和 <font style="font-size: 12pt;"><span style="color: rgb(173, 0, 0); font-size: 12pt; font-weight: bold;">Semaphore 对象</span></font>，一个 RLock （可重入锁）可以被同一个线程多次获取，主要用来实现基于监测对象模式的锁定和同步。在使用这种锁的情况下，当锁被持有时，只有一个线程可以使用完整的函数或者类中的方法。</div></div><div style="text-align: left;"><br/></div><div style="text-align: left;"><div>相对于简单地作为锁使用，信号量更适用于那些需要在线程之间<font style="font-size: 12pt;"><span style="color: rgb(173, 0, 0); font-size: 12pt; font-weight: bold;">引入信号</span></font>或者限制的程序。比如，你需要限制一段代码的并发访问量，你就可以像下面这样使用信号量完成：</div></div><div style="text-align: left;"><br/></div><div style="box-sizing: border-box; padding: 8px; font-size: 12px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902);"><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">from threading import Semaphore</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">import urllib.request</span></div><div><br/></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;"># At most, five threads allowed to run at once_fetch_url_sema = Semaphore(5)</span></div><div><br/></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">def fetch_url(url):</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">    with _fetch_url_sema:</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">        return urllib.request.urlopen(url)</span></div><div><br/></div></div><div style="text-align: left;"><br/></div><div style="text-align: center;"><br/></div><div style="text-align: center;"></div><h1 style="text-align: left;"><span style="color: rgb(28, 51, 135); font-weight: bold; font-size: 18pt;">防止死锁的加锁机制</span></h1><div>写一个多线程程序，其中线程需要一次获取多个锁，此时如何避免死锁问题</div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div style="text-align: center;"><div><br/></div></div></div><div><br/></div></span>
</div></body></html> 